/**
 * Copyright (C),2011-2012,北京国电通网络技术有限公司.
 * FileName:	global.cpp
 * Author:		LiuHaifeng
 * Version:		V0.1
 * Date:		2011-11-15
 * Description	The file describes all the global variables used frequently in all .cpp file, and do some initialize.
 */

/**
 * History:
 * 		Author		date		Version		Description
 *    LiuHaifeng  2012-02-20	  V0.4      add freescale macro definition
 */

#include "global.h"
#include "../main/downLoop.h"
#include "../main/upLoop.h"
#include "../serial/serial.h"
#include "../sqlite/sqlite.h"

struct StEquipList g_devList;
struct StDownTask g_downTask;
struct StUpTask g_upTask;
struct StSerialFD g_serialFD;
struct StDataTransmit g_dataTrans;
struct StOther g_other;
struct StDeadTimeTask g_deadTimeTask;
struct StDelay g_sendDelay;
struct StLED g_LED;
int flagAddress=0;                                ///flagAddress=0 set time;
bool upGradeKit=false;                            ///up grade flag

int optTimes=0;                                 ///the numbers of operation times
int optBegin_time=0;                           ///first record time

int setLed_ON=1;    						  ///LED on just for freescale
int setLed_OFF=0;							 ///LED off just for freescale

static void initSocStatus();

/***globalInit() brief initialization function
 * param void
 *
 * retval int,0 if successfully -1 if failed
 ***/
int globalInit()
{
	PRINTOUT("%s","in globalInit()");
	int l_tmpTime;
	////////////////////////////////////////////// open LED status lamb
#ifndef DEBUG_PC
	g_LED.st_status = open(LED_STATUS,O_RDWR);
	if (g_LED.st_status< 0)
	{
		ERROROUT("can not open status led device");
		//return 0;													///if error, just go on
	}
#ifdef FREESCALE
	write(g_LED.st_status,&setLed_ON,1);
#else
	ioctl(g_LED.st_status, SET_LED_ON, NULL);
#endif
	g_LED.st_mod2 = open(LED_MOD2,O_RDWR);
	if (g_LED.st_mod2< 0)
	{
		ERROROUT("can not open mod2 led device");
		//return 0;
	}
	g_LED.st_mod3 = open(LED_MOD3,O_RDWR);
	if (g_LED.st_mod3< 0)
	{
		ERROROUT("can not open mod3 led device");
		//return 0;
	}
#endif
	////////////////////////////////////////initialize sqlite-database/////////////////////////////////////////
	if(-1==sqliteInit())
	{
		ERROROUT("initialize database failed!");
		return -1;
	}
	////////////////////////////////////////initialize 'struct StEquipList'////////////////////////////////////
	memset(g_devList.st_equipArray,0,EQUIPMENT_NUM*sizeof(struct StEquipment));
	///initialize g_devList.st_empty
	if(-1==sem_init(&(g_devList.st_empty.st_sem),0,1))		///can be used by only one process(magic 0),and initial value is 1;
	{
		ERROROUT("g_devList.st_devlistSem init failed!");
		return -1;
	}
	g_devList.st_empty.type=StEquipList_empty;
	g_devList.st_empty.head=0;
	for(int i=0;i<EQUIPMENT_NUM-1;i++)
	{
		g_devList.st_equipArray[i].next=i+1;
		g_devList.st_equipArray[i].socketStatus=sta_unknown;		///status unknown
		g_devList.st_equipArray[i].elecQueryStatus=sta_no;
		g_devList.st_equipArray[i].activeQueryStatus=sta_no;
		g_devList.st_equipArray[i].firstElec=equ_yes;
	}
	g_devList.st_equipArray[EQUIPMENT_NUM-1].socketStatus=sta_unknown;
	g_devList.st_equipArray[EQUIPMENT_NUM-1].elecQueryStatus=sta_no;
	g_devList.st_equipArray[EQUIPMENT_NUM-1].activeQueryStatus=sta_no;
	g_devList.st_equipArray[EQUIPMENT_NUM-1].firstElec=equ_yes;
	g_devList.st_equipArray[EQUIPMENT_NUM-1].next=NO_MORE;			///no next element
	///initialize g_devList.st_equip
	if(-1==sem_init(&(g_devList.st_equip.st_sem),0,1))
	{
		ERROROUT("g_devList.st_devlistSem init failed!");
		return -1;
	}
	g_devList.st_equip.type=StEquipList_equip;
	g_devList.st_equip.head=NO_MORE;

	if(-1==initEquipFromSqlite())							///initialize 'g_devList.st_equip'
	{
		ERROROUT("equipment list initialize failed!");
		return -1;
	}
	////////////////////////////////////////initialize 'struct StDownTask'/////////////////////////////////////
	memset(g_downTask.st_command,0,CONTROLCMD_NUM*sizeof(struct StControlCmd));
	///initialize g_downTask.st_task
	if(-1==sem_init(&(g_downTask.st_task.st_sem),0,1))
	{
		ERROROUT("g_downTask.st_task init failed!");
		return -1;
	}
	g_downTask.st_task.type=StDownTask_task;
	g_downTask.st_task.head=NO_MORE;
	///initialize g_downTask.st_timeTask
	if(-1==sem_init(&(g_downTask.st_timeTask.st_sem),0,1))
	{
		ERROROUT("g_downTask.st_timeTask init failed!");
		return -1;
	}
	g_downTask.st_timeTask.type=StDownTask_timeTask;
	g_downTask.st_timeTask.head=NO_MORE;
	///initialize g_downTask.st_emtpy
	if(-1==sem_init(&(g_downTask.st_emtpy.st_sem),0,1))
	{
		ERROROUT("g_downTask.st_emtpy init failed!");
		return -1;
	}
	g_downTask.st_emtpy.head=0;
	g_downTask.st_emtpy.type=StDownTask_emtpy;
	for(int i=0;i<CONTROLCMD_NUM-1;i++)
	{
		g_downTask.st_command[i].next=i+1;
	}
	g_downTask.st_command[CONTROLCMD_NUM-1].next=NO_MORE;

	////////////////////////////////////////initialize 'struct StUpTask'///////////////////////////////////////
	memset(g_upTask.st_recvData,0,RECVRESULT_NUM*sizeof(struct StReplyData));
	///initialize g_upTask.st_safeguardList
	if(-1==sem_init(&(g_upTask.st_safeguardList.st_sem),0,1))
	{
		ERROROUT("g_upTask.st_safeguardList init failed!");
		return -1;
	}
	g_upTask.st_safeguardList.type=StUpTask_safeguardList;
	g_upTask.st_safeguardList.head=NO_MORE;
	///initialize g_upTask.st_emtpy
	if(-1==sem_init(&(g_upTask.st_emtpy.st_sem),0,1))
	{
		ERROROUT("g_upTask.st_emtpy init failed!");
		return -1;
	}
	g_upTask.st_emtpy.type=StUpTask_emtpy;
	g_upTask.st_emtpy.head=0;
	for(int i=0;i<RECVRESULT_NUM-1;i++)
	{
		g_upTask.st_recvData[i].next=i+1;
		g_upTask.st_recvData[i].data.safeGuard.sendFlag=false;
	}
	g_upTask.st_recvData[RECVRESULT_NUM-1].next=NO_MORE;
	g_upTask.st_recvData[RECVRESULT_NUM-1].data.safeGuard.sendFlag=false;

	////////////////////////////////////////initialize 'struct StSerialFD'/////////////////////////////////////
#if defined SMARTHOME_DEBUG
#ifdef DEBUG_PC
	g_serialFD.st_serial0=-1;
	g_serialFD.st_serial0=openPort(1,B115200,8,1,'N');
	if(-1==g_serialFD.st_serial0)
	{
		ERROROUT("open ttyS0 failed!");
		return -1;
	}
#elif defined DEBUG_SOCKET
	g_serialFD.st_serial1=-1;
	g_serialFD.st_serial1=openPort(1,B9600,8,1,'N'); 
	if(-1==g_serialFD.st_serial1)
	{
		ERROROUT("open ttyS1 failed!");
		return -1;
	}
#elif defined DEBUG_ARM
	g_serialFD.st_serial1=-1;
	g_serialFD.st_serial2=-1;
	g_serialFD.st_serial3=-1;
	/* 2012-02-10 V0.4 modify by LiuHaifeng begin */
#if defined BSERIAL1
	#ifdef FREESCALE
	g_serialFD.st_serial1=openPort(0,B115200,8,1,'N');			///just for freescale
	#else
	g_serialFD.st_serial1=openPort(1,B115200,8,1,'N'); 
	#endif
#else
	#ifdef FREESCALE
	g_serialFD.st_serial1=openPort(0,B9600,8,1,'N');			///just for freescale
	#else
	g_serialFD.st_serial1=openPort(1,B9600,8,1,'N'); 
	#endif
#endif
	/* 2012-02-10 V0.4 modify by LiuHaifeng end */

	if(-1==g_serialFD.st_serial1)
	{
		#ifdef FREESCALE
		ERROROUT("open ttyS0 failed!");
		#else
		ERROROUT("open ttyS1 failed!");
		#endif
		return -1;
	}
#if defined DINAIKE
	g_serialFD.st_serial2=openPort(2,B4800,8,1,'N');
#else
	g_serialFD.st_serial2=openPort(2,B9600,8,1,'N');
#endif
	if(-1==g_serialFD.st_serial2)
	{
		ERROROUT("open ttyS2 failed!");
		return -1;
	}
	g_serialFD.st_serial3=openPort(3,B9600,8,1,'N');
	if(-1==g_serialFD.st_serial3)
	{
		ERROROUT("open ttyS3 failed!");
		return -1;
	}
#endif
#elif defined NO_DEBUG_SOCKET
	g_serialFD.st_serial1=-1;
	g_serialFD.st_serial1=openPort(1,B9600,8,1,'N'); 
	if(-1==g_serialFD.st_serial1)
	{
		ERROROUT("open ttyS1 failed!");
		return -1;
	}
#elif defined NO_DEBUG_ALL
	g_serialFD.st_serial1=-1;
	g_serialFD.st_serial2=-1;
	g_serialFD.st_serial3=-1;
	g_serialFD.st_serial1=openPort(1,B9600,8,1,'N'); 
	if(-1==g_serialFD.st_serial1)
	{
		ERROROUT("open ttyS1 failed!");
		return -1;
	}
#if defined DINAIKE
	g_serialFD.st_serial2=openPort(2,B4800,8,1,'N');
#else
	g_serialFD.st_serial2=openPort(2,B9600,8,1,'N');
#endif
	if(-1==g_serialFD.st_serial2)
	{
		ERROROUT("open ttyS2 failed!");
		return -1;
	}
	g_serialFD.st_serial3=openPort(3,B9600,8,1,'N');
	if(-1==g_serialFD.st_serial3)
	{
		ERROROUT("open ttyS3 failed!");
		return -1;
	}
#endif
	////////////////////////////////////////initialize 'struct StDataTransmit'/////////////////////////////////
	memset(g_dataTrans.st_sendSerial,0,SENDSERIAL_NUM);
	////////////////////////////////////////initialize 'struct StDeadTimeTask'/////////////////////////////////
	struct timeval l_tv;
	if(-1==gettimeofday(&l_tv,NULL))
	{
		ERROROUT("get-time failed!");
		return -1;
	}
	g_deadTimeTask.st_inquiryElec=l_tv.tv_sec/(ELECGETINTERVAL)*(ELECGETINTERVAL)+ELECGETPOINT;		///define inquiry elec time
	g_deadTimeTask.st_inquiryYGGL=l_tv.tv_sec/(YGGLGETINTERVAL)*(YGGLGETINTERVAL)+YGGLGETPOINT;     ///define inquiry active power time
	///adjust time stamp
	l_tmpTime=getTodayZero(l_tv.tv_sec);
	g_deadTimeTask.st_syncTimeTask=l_tmpTime+5;
	////////////////////////////////////////initialize 'struct StDelay'////////////////////////////////////////
	g_sendDelay.st_smart=false;
	g_sendDelay.st_lastSend=l_tv;
	////////////////////////////////////////initialize 'struct StOther'////////////////////////////////////////
	g_other.st_charToUnsignedFlag=true;
	g_other.st_pCmdOther=NULL;
	g_other.st_shmFD=-1;
	g_other.st_shmADDR=NULL;
	////////////////////////////////////////create shared map//////////////////////////////////////////////////
	///open a file used as shared memory.
	g_other.st_shmFD=open(SHARENAME,O_CREAT|O_RDWR|O_TRUNC,0777);
	if(-1==g_other.st_shmFD)
	{
		ERROROUT("open file failed!");
		return -1;
	}
	write(g_other.st_shmFD,0,1);	///make sure 'g_addr[0]=0'
	if(-1==lseek(g_other.st_shmFD,SHARESIZE-1,SEEK_SET))			///this is needed.
	{
		ERROROUT("lseek failed!");
		return -1;
	}
	write(g_other.st_shmFD,"",1);	///this is needed. or will appear an error--"bus error". Because file has been open, but it has no size, in mmap require size.
	///share memory.---return void*
	g_other.st_shmADDR = (char*)mmap( NULL,SHARESIZE,PROT_READ|PROT_WRITE,MAP_SHARED,g_other.st_shmFD,0 );
	if (g_other.st_shmADDR==MAP_FAILED)
	{
		ERROROUT("mmap failed!");
		return -1;
	}
	memset(g_other.st_shmADDR,0,SHARESIZE);
	////////////////////////////////////////create another two thread//////////////////////////////////////////
	typedef void*(*format)(void *);													///define function pointer of "void*(name)(void*)"
	pthread_t l_downlinkthread,l_uplinkthread,l_safeguardlinkthread;										///the file description of thread
	pthread_attr_t l_attrthread;													///the attribute of thread
	///start other three thread.
	pthread_attr_init(&l_attrthread);												///initialize attribute
	pthread_attr_setscope(&l_attrthread,PTHREAD_SCOPE_SYSTEM);						///set attribute binding
	pthread_attr_setdetachstate(&l_attrthread,PTHREAD_CREATE_DETACHED);				///set attribute detached
	if(-1==pthread_create(&l_downlinkthread,&l_attrthread,(format)downLoopHandler,NULL))
	{
		ERROROUT("thread2 create failed!");
		return -1;
	}
	if(-1==pthread_create(&l_uplinkthread,&l_attrthread,(format)upLoopHandler,NULL))
	{
		ERROROUT("thread3 create failed!");
		return -1;
	}
	if(-1==pthread_create(&l_safeguardlinkthread,&l_attrthread,(format)safeguardHandler,NULL))
	{
		ERROROUT("thread4 create failed!");
		return -1;
	}
	pthread_attr_destroy(&l_attrthread);
	///wait until thread start
	myDelay(500);
	////////////////////////////////////////done something initialization//////////////////////////////////////
	///inquriy all socket's status
	initSocStatus();
	///wait until status finish
	myDelay(1000);

	return 0;
}
/***initSocStatus() brief inquiry socket's status when initialize
 * param void
 *
 * retval void
 ***/
static void initSocStatus()
{
	int l_sendNum;
	PRINTOUT("%s","initialize socket status.");
	for(int l_devPos=g_devList.st_equip.head;l_devPos!=NO_MORE;l_devPos=g_devList.st_equipArray[l_devPos].next)
	{
		if((g_devList.st_equipArray[l_devPos].equipmentID[0]==0x00 && g_devList.st_equipArray[l_devPos].equipmentID[1]==0x00 \
				&& g_devList.st_equipArray[l_devPos].equipmentID[2]==0x00 && g_devList.st_equipArray[l_devPos].equipmentID[3]==0x00\
				&& g_devList.st_equipArray[l_devPos].equipmentID[4]==0x00 && g_devList.st_equipArray[l_devPos].equipmentID[5]==0x00)\
				||((g_devList.st_equipArray[l_devPos].typeID >> 12 & 0xf) == 0xf))
		///make sure socket's address mustn't empty or not safeguard
			continue;

		l_sendNum=0;					///re initialize
		///send serial
		g_dataTrans.st_sendSerial[l_sendNum++]=0x68;
		g_dataTrans.st_sendSerial[l_sendNum++]=g_devList.st_equipArray[l_devPos].equipmentID[0];
		g_dataTrans.st_sendSerial[l_sendNum++]=g_devList.st_equipArray[l_devPos].equipmentID[1];
		g_dataTrans.st_sendSerial[l_sendNum++]=g_devList.st_equipArray[l_devPos].equipmentID[2];
		g_dataTrans.st_sendSerial[l_sendNum++]=g_devList.st_equipArray[l_devPos].equipmentID[3];
		g_dataTrans.st_sendSerial[l_sendNum++]=g_devList.st_equipArray[l_devPos].equipmentID[4];
		g_dataTrans.st_sendSerial[l_sendNum++]=g_devList.st_equipArray[l_devPos].equipmentID[5];
		g_dataTrans.st_sendSerial[l_sendNum++]=0x68;
		g_dataTrans.st_sendSerial[l_sendNum++]=0x01;
		g_dataTrans.st_sendSerial[l_sendNum++]=0x02;
		g_dataTrans.st_sendSerial[l_sendNum++]=0x93;
		g_dataTrans.st_sendSerial[l_sendNum++]=0xe9;
		g_dataTrans.st_sendSerial[l_sendNum]=creatChecksum(l_sendNum);
		g_dataTrans.st_sendSerial[++l_sendNum]=0x16;
		++l_sendNum;

		myDelay(needDelay(0));
		if(!sendSerial(l_sendNum))
		{
			ERROROUT("sendSerial() failed!");
			continue;					///if failed, just ignore
		}
	}
}
